package jmine.tec.executionlog.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jmine.tec.executionlog.domain.ExecutionLog;
import jmine.tec.executionlog.domain.enumx.ExecutionStatus;
import jmine.tec.utils.date.Interval;
import jmine.tec.utils.date.IntervalAggregator;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import bancosys.tec.persist.dao.BaseDAO;
import bancosys.tec.persist.dataset.HibernateRandomAccessResultSet;
import bancosys.tec.utils.date.Date;
import bancosys.tec.utils.date.DateUtils;
import bancosys.tec.utils.date.Timestamp;

/**
 * DAO de Log de execucao de Data Digester.
 * 
 * @author Marcio Ribeiro (mmr)
 * @created Jun 19, 2008
 */
public class ExecutionLogDAO extends BaseDAO<ExecutionLog> {
    /**
     * Encontra logs de execucao para o intervalo de tempo passado.
     * 
     * @param startTime inicio.
     * @param endTime fim.
     * @return logs para o periodo.
     */
    public List<ExecutionLog> findByExecutionTime(Timestamp startTime, Timestamp endTime) {
        Criteria crit = this.getSession().createCriteria(ExecutionLog.class);

        if (startTime != null) {
            crit.add(Restrictions.ge("executionStartTime", startTime));
        }

        if (endTime != null) {
            crit.add(Restrictions.le("executionEndTime", endTime));
        }

        crit.addOrder(Order.desc("executionStartTime"));
        return this.executeQuery(crit);
    }

    /**
     * Encontra execucoes para o intervalo de tempo passado.
     * 
     * @param fileCode tipo do arquivo
     * @param status status
     * @param startTime inicio.
     * @param endTime fim.
     * @return execucoes.
     */
    public List<ExecutionLog> findByTipoArquivoStatusTimestamp(String fileCode, ExecutionStatus status, Timestamp startTime,
            Timestamp endTime) {
        Criteria crit = this.createCriteria();

        if (fileCode != null) {
            crit.add(Restrictions.eq("fileCode", fileCode));
        }

        if (status != null) {
            crit.add(Restrictions.eq("status", status));
        }

        if (startTime != null) {
            crit.add(Restrictions.ge("executionStartTime", startTime));
        }

        if (endTime != null) {
            crit.add(Restrictions.le("executionEndTime", endTime));
        }

        crit.addOrder(Order.desc("executionStartTime"));
        return this.executeQuery(crit);
    }

    /**
     * Encontra execucoes cuja data do arquivo corresponda a data passada.
     * 
     * @param fileCode tipo do arquivo.
     * @param fileDate data dos dados do arquivo.
     * @return as execucoes.
     */
    public List<ExecutionLog> findByTipoArquivoData(String fileCode, Date fileDate) {
        Criteria crit = this.createCriteria();

        if (fileCode != null) {
            crit.add(Restrictions.eq("fileCode", fileCode));
        }

        if (fileDate != null) {
            crit.add(Restrictions.eq("fileDate", fileDate));
        }

        crit.addOrder(Order.desc("executionStartTime"));
        return this.executeQuery(crit);
    }

    /**
     * Encontra execucoes cuja data do arquivo estaja entra as datas passadas.
     * 
     * @param fileCode tipo do arquivo.
     * @param startfileDate data inicial dos dados do arquivo.
     * @param endfileDate data final dos dados do arquivo.
     * @return as execucoes.
     */
    public List<ExecutionLog> findByTipoArquivoDatas(String fileCode, Date startfileDate, Date endfileDate) {
        Criteria crit = this.createCriteria();

        if (fileCode != null) {
            crit.add(Restrictions.eq("fileCode", fileCode));
        }

        if (startfileDate != null) {
            crit.add(Restrictions.ge("fileDate", startfileDate));
        }

        if (endfileDate != null) {
            crit.add(Restrictions.le("fileDate", endfileDate));
        }

        crit.addOrder(Order.desc("executionStartTime"));
        return this.executeQuery(crit);
    }

    /**
     * Executa query que seleciona e remove diretamente no banco os registros até a data especificada.
     * 
     * @param tsData Timestamp da data de inicio do log.
     */
    @SuppressWarnings("deprecation")
    public void removeByData(Timestamp tsData) {
        String query1 =
                "delete from ExecutionLogItem e where e.executionLog.id in "
                        + "(select id from ExecutionLog el where el.executionStartTime <= :tsData)";
        String query2 = "delete from ExecutionLog el where el.executionStartTime <= :tsData)";

        Map<String, Object> parametros = new HashMap<String, Object>();
        parametros.put("tsData", tsData);
        this.executeUpdate(query1, parametros);
        this.executeUpdate(query2, parametros);
    }

    /**
     * Devolve bean com tempos de importacao de arquivo.
     * 
     * @param daysToConsider dias a considerar para pesquisa dos tempos.
     * @param fileCode tipo de arquivo para filtro.
     * @return bean com tempos.
     */
    public IntervalAggregator findLastExecutionLogTimes(int daysToConsider, String fileCode) {
        String qs = "SELECT new jmine.tec.utils.date.Interval(executionStartTime, executionEndTime) FROM ExecutionLog WHERE ";
        qs += " fileCode = :fileCode AND executionEndTime > :ini";

        Query q = getSession().createQuery(qs);
        q.setParameter("fileCode", fileCode);
        q.setParameter("ini", DateUtils.createTimestampWithLastSecondOfTheDay(new Date().addDays(-daysToConsider - 1)));

        return new IntervalAggregator(new HibernateRandomAccessResultSet<Interval>(getSession(), q));
    }
}
